package com.runner.sound;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.math.MathUtils;
import com.runner.observer.Event;
import com.runner.observer.Observer;
import com.runner.observer.Subject;
import com.runner.utility.Constants;
import com.runner.utility.Locator;

public class AudioManager implements Constants, Observer {

	public float SWITCH_MUSIC_TIME = 1;
	public float DEFAULT_VOLUME = 0.5f;

	private float musicVolume;
	private float effectsVolume;
	private float previousMusicVolume;
	private float previousEffectsVolume;
	private ArrayList<Music> musicList;
	private Music currentMusic;
	private Music menuMusic;
	private IAudio audio;
	private Subject subject;
	private boolean switchingMusic;
	private boolean loopMusic1;

	private Map<String, Sound> soundList;

	public AudioManager(IAudio audio, boolean mute, Subject subject) {
		this.audio = audio;
		this.subject = subject;
		switchingMusic = true;
		loopMusic1 = true;
		musicVolume = previousMusicVolume = DEFAULT_VOLUME;
		effectsVolume = previousEffectsVolume = DEFAULT_VOLUME;
		subject.addObserver(this);
		musicList = new ArrayList<Music>();
		musicList.add(Locator.getAssets().get(MUSIC1, Music.class));
		musicList.add(Locator.getAssets().get(MUSIC2, Music.class));
		currentMusic = musicList.get(MathUtils.random(0, musicList.size() - 1));

		menuMusic = Locator.getAssets().get(MENU_MUSIC, Music.class);
		if (mute) {
			mute();
		}

		initSounds();
	}

	public void pickMusic() {
		// loop music track 1 once because its short otherwise alternate
		// (only works with 2 songs)
		if (currentMusic.equals(musicList.get(0))) {
			if (loopMusic1) {
				loopMusic1 = false;
				SWITCH_MUSIC_TIME = 1;
			} else {
				currentMusic = musicList.get(1);
				SWITCH_MUSIC_TIME = 1;
				loopMusic1 = true;
			}
		} else if (currentMusic.equals(musicList.get(1))) {
			currentMusic = musicList.get(0);
			SWITCH_MUSIC_TIME = 0;
		}
	}

	public void mute() {
		Locator.setMute(true);
		effectsVolume = 0;
		musicVolume = 0;
		audio.setMusicVolume(musicVolume);
	}

	public void unmute() {
		Locator.setMute(false);
		musicVolume = previousMusicVolume;
		effectsVolume = previousEffectsVolume;
		audio.setMusicVolume(musicVolume);
	}

	@Override
	public void onNotify(Event event) {
		switch (event) {
		case EVENT_CLICK:
			audio.playSound(soundList.get(MENU_CLICK), effectsVolume);
			break;
		case EVENT_MENU_MUSIC_FINISHED:
			Locator.scheduleEvent(SWITCH_MUSIC_TIME, Event.EVENT_START_MENU, subject);
			switchingMusic = true;
			break;
		case EVENT_MUSIC_FINISHED:
			Locator.scheduleEvent(SWITCH_MUSIC_TIME, Event.EVENT_PICK_MUSIC, subject);
			switchingMusic = true;
			break;
		case EVENT_STOP_MUSIC:
			audio.stopMusic();
			break;
		case EVENT_PICK_MUSIC:
			if (switchingMusic) {
				audio.stopMusic();
				pickMusic();
				audio.playMusic(currentMusic, musicVolume);
				switchingMusic = false;
			}
			break;
		case EVENT_MENU_TO_GAME:
			audio.stopMusic();
			pickMusic();
			audio.playMusic(currentMusic, musicVolume);
			break;
		case EVENT_START_MENU:
			if (switchingMusic) {
				audio.stopMusic();
				audio.playMusic(menuMusic, musicVolume);
				switchingMusic = false;
			}
			break;
		case EVENT_GAME_TO_MENU:
			audio.stopMusic();
			audio.playMusic(menuMusic, musicVolume);
			break;
		case EVENT_INSUFFICIENT_COINS:
			audio.playSound(soundList.get(NO_COINS_SOUND), effectsVolume);
			break;
		case EVENT_UNLOCK:
			audio.playSound(soundList.get(UNLOCK_SOUND), effectsVolume);
			break;
		case EVENT_ROLL:
			audio.playSound(soundList.get(JUMP_SOUND), effectsVolume);
			break;

		case EVENT_JUMP:
			audio.playSound(soundList.get(JUMP_SOUND), effectsVolume);
			break;
		case EVENT_DOUBLE_JUMP:
			audio.playSound(soundList.get(DOUBLE_JUMP_SOUND), effectsVolume);
			break;
		case EVENT_COIN:
			audio.playSound(soundList.get(COIN_SOUND), effectsVolume);
			break;

		case HIT_WITH_SHIELD:
		case EVENT_DEATH:
			audio.playSound(soundList.get(HIT_SOUND), effectsVolume);
			break;
		case EVENT_WIN:
			audio.playSound(soundList.get(WIN_SOUND), effectsVolume);
			break;
		case EVENT_DIVE:
			audio.playSound(soundList.get(JUMP_SOUND), effectsVolume);
			break;
		case EVENT_NEW_TOP_DISTANCE:
			audio.playSound(soundList.get(TOP_SOUND), effectsVolume);
			break;
		default:
			break;
		}
	}

	private void initSounds() {
		soundList = new HashMap<String, Sound>();
		soundList.put(MENU_CLICK, Locator.getAssets().get(MENU_CLICK, Sound.class));
		soundList.put(NO_COINS_SOUND, Locator.getAssets().get(NO_COINS_SOUND, Sound.class));
		soundList.put(COIN_SOUND, Locator.getAssets().get(COIN_SOUND, Sound.class));
		soundList.put(WIN_SOUND, Locator.getAssets().get(WIN_SOUND, Sound.class));
		soundList.put(JUMP_SOUND, Locator.getAssets().get(JUMP_SOUND, Sound.class));
		soundList.put(DOUBLE_JUMP_SOUND, Locator.getAssets().get(DOUBLE_JUMP_SOUND, Sound.class));
		soundList.put(HIT_SOUND, Locator.getAssets().get(HIT_SOUND, Sound.class));
		soundList.put(UNLOCK_SOUND, Locator.getAssets().get(UNLOCK_SOUND, Sound.class));
		soundList.put(TOP_SOUND, Locator.getAssets().get(TOP_SOUND, Sound.class));
	}

	public boolean isPlayingMenuMusic() {
		return menuMusic.isPlaying();
	}

	public boolean isPlayingGameMusic() {
		return currentMusic.isPlaying();
	}

	public boolean isSwitchingMusic() {
		return switchingMusic;
	}

}
